// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`timescale 1 ps / 1 ps
module espi_slave #(
    parameter DEVICE_FAMILY             = "MAX 10 FPGA",
    parameter IO_MODE_RANGE             = 2'b11,
    parameter OPEN_DRAIN_ALERT_EN       = 1'b0,
    parameter MAX_FREQ_RANGE            = 3'b000,
    parameter CHANNEL_SUPPORT           = 8'b00000111,
    parameter MAX_PC_PAYLOAD_SIZE_RANGE = 3'b001,
    parameter MAX_PC_READREQ_SIZE_RANGE = 3'b001,
    parameter MAX_OOB_PAYLOAD_SIZE_RANGE = 3'b001,
    parameter MAX_VW_COUNT_SUPPORTED    = 6'b000111
) (
    input                clk,
    input                reset_n,
    // avalon protocol
    input                avmm_write,
    input                avmm_read,
    input [31:0]         avmm_writedata,
    input [4:0]          avmm_address,
    output logic [31:0]  avmm_readdata,
    output logic         avmm_readdatavalid,
    // 
    // eSPI Memory Read/Write interface (Avalon Memory Mapped Master)
    output logic         mem_reset,
    output logic [31:0]  mem_address,
    output logic         mem_write,
    output logic [31:0]  mem_writedata,
    output logic [3:0]   mem_byteenable,
    output logic         mem_read,
    input logic [31:0]   mem_readdata,
    input logic          mem_waitrequest,
    // 
    // eSPI I/O Read/Write Short interface (Avalon Memory Mapped Master)
    output logic         io_reset,
    output logic [15:0]  io_address,
    output logic         io_write,
    output logic [7:0]   io_writedata,
    output logic         io_read,
    input logic [7:0]    io_readdata,
    input logic          io_waitrequest,

    // interrupt
    output logic         irq,
    output logic         oob_rxfifo_avail,

    // espi protocol
    input                espi_clk,
    input                espi_reset_n,
    input                espi_cs_n,
    input [3:0]          espi_data_in,
    output [3:0]         espi_data_out,
    output logic         espi_alert_n,

    // Virtual Wire external inputs & outputs
    input logic [255:0]  vw_irq, // Interrupt requests
    input logic [255:0]  vw_plti, // Platform-specific system inputs
    output logic [255:0] vw_plto, // Platform-specific system outputs
    input logic [511:0]  vw_gpi, // General-Purpose inputs
    output logic [511:0] vw_gpo, // General-Purpose outputs

    // conduit
    output logic         slp_s3_n,
    output logic         slp_s4_n,
    output logic         slp_s5_n,
    output logic         sus_stat_n,
    output logic         pltrst_n,
    output logic         oob_rst_warn,
    output logic         host_rst_warn,
    output logic         smiout_n,
    output logic         nmiout_n,
    input                slave_boot_load_done,
    input                slave_boot_load_status,
    input                oob_rst_ack,
    input                wake_n,
    input                nmi_n,
    input                pme_n,
    input                sci_n,
    input                smi_n,
    input                rcin_n,
    input                host_rst_ack,
    input                rsmrst_n,

    input                error_nonfatal,
    input                error_fatal,

    // output FPGA_ESPI_BASE read only registers for access through avmm i/f
    output logic [31:0]  device_id_reg,
    output logic [31:0]  general_config_reg,
    output logic [31:0]  channel0_config_reg,
    output logic [31:0]  channel1_config_reg,
    output logic [31:0]  channel2_config_reg,
    output logic [31:0]  channel3_config_reg
);

localparam PC_RXFIFO_SIZE = 256;

localparam PC_TXFIFO_SIZE = 256;
    

    localparam VW_FIFO_SIZE = 32;
    localparam VW_FIFO_WIDTHU = $clog2(VW_FIFO_SIZE);
    localparam PC_RXFIFO_WIDTHU = $clog2(PC_RXFIFO_SIZE);
    localparam PC_TXFIFO_WIDTHU = $clog2(PC_TXFIFO_SIZE);
    localparam OOB_RXFIFO_SIZE = 256;
    localparam OOB_TXFIFO_SIZE = 256;
    localparam OOB_RXFIFO_WIDTHU = $clog2(OOB_RXFIFO_SIZE);
    localparam OOB_TXFIFO_WIDTHU = $clog2(OOB_TXFIFO_SIZE);
    localparam DATABYTE_ARR = 4;            //max is 4 byte for status data byte
    localparam HDRBYTE_ARR  = 4;            //max is 4 byte because length byte is in byte1 and byte2
    localparam BYTE      = 8;

    // espi_condt_det outputs
    logic [7:0]     rxshift_data;
    logic           trigger_output;
    logic           espi_cs_n_nxt2;
    logic           invalid_cs_deassertion;
    logic           start_det;
    logic           stop_det;
    logic           spiclk_cnt_done_lh;
    logic           spiclk_cnt_done_hl;

    // espi_rx_shifter outputs
    logic [1:0]     rx_hdr_array_cnt;
    logic [2:0]     rx_data_array_cnt;
    logic [7:0]     command_byte;
    logic [7:0]     header_byte[HDRBYTE_ARR];
    logic [7:0]     data_byte[DATABYTE_ARR];
    logic [7:0]     crc_byte;
    logic [4:0]     cycletype_byte;
    logic [2:0]     cmd_cycletype_msb;
    logic [6:0]     length_byte;
    logic [63:0]    addr_byte;
    logic           rx_detect_command;
    logic           rx_detect_header;
    logic           rx_detect_data;
    logic           rx_detect_crc;
    logic           rx_detect_cycletype_end;
    logic           rx_detect_command_end;
    logic           rx_detect_header_end;
    logic           rx_detect_data_end;
    logic           rx_detect_crc_end;
    logic           detect_rx_idle;

    // espi_tx_shifter outputs
    logic           detect_tx_idle;
    logic [7:0]     tx_dataout_byte;
    logic           tx_gen_command;
    logic           tx_gen_header;
    logic           tx_gen_cycletype;
    logic           tx_gen_length_h;
    logic           tx_gen_length_l;
    logic           tx_gen_data;
    logic [2:0]     tx_data_array_cnt;
    logic           tx_gen_status;
    logic           tx_gen_crc;
    logic           np_connected;
    logic [1:0]     tx_status_cnt;

    // espi_cmd_det outputs
    logic [15:0]    config_reg_addr;
    logic [31:0]    config_reg_datain;
    logic [3:0]     cmd_hdr_ptr;
    logic [6:0]     cmd_data_ptr;
    logic [2:0]     cmd_data_array;
    logic           detect_getvwire;
    logic           detect_getstatus;
    logic           detect_getconfig;
    logic           detect_setconfig;
    logic           detect_putpc;
    logic           detect_putnp;
    logic           detect_getpc;
    logic           detect_getnp;
    logic           detect_putvwire;
    logic           detect_put_np_rxfifo;
    logic           detect_put_pc_rxfifo;
    logic           detect_get_np_txfifo;
    logic           detect_get_pc_txfifo;
    logic           detect_pc_cmd_withdata;
    logic           detect_iord_short;
    logic           detect_iowr_short;
    logic           detect_short_1b;
    logic           detect_short_2b;
    logic           detect_short_4b;
    logic           detect_memrd_short;
    logic           detect_memwr_short;
    logic           detect_reset;
    logic           detect_putoob;
    logic           detect_getoob;
    logic           detect_put_oob_rxfifo;
    logic           detect_get_oob_txfifo;
    logic           posted_cycle;
    logic           invalid_cmd;
    logic           invalid_cycletype;
    logic           rx_with_cycletype;
    logic [7:0]     vw_data_ptr;
    logic [3:0]     addr_ptr;

    // espi_register outputs
    logic [3:0]     max_wait_state;
    logic [1:0]     io_mode;
    logic [15:0]    status_reg_dataout;
    logic [31:0]    config_reg_dataout;
    logic           crc_en;
    logic           resp_mod_en;
    logic           alert_mode;
    logic           opendrain_alert;
    logic [2:0]     freq_value;
    logic [2:0]     max_pc_payload_size;
    logic [2:0]     max_pc_readreq_size;
    logic           bus_master_en;
    logic           pc_channel_en;
    logic [2:0]     max_oob_payload_size;
    logic [5:0]     max_vw_count;
    logic           oob_channel_en;
    logic           vw_channel_en;
    logic           update_status_reg;
    logic           oob_txfifo_avail;
    logic           interrupt;
    logic           pc_channel_reset;
    logic           oob_channel_reset;
    logic [2:0]     avalon_status_reg;
    logic [7:0]     error_reg;
    logic [15:0]    espi_status_reg;

    // espi_resp_gen
    logic [7:0]     resp_header;
    logic [4:0]     resp_cycletype;
    logic [2:0]     resp_cycletype_msb;
    logic [7:0]     resp_data[4];
    logic [7:0]     resp_status[2];
    logic [3:0]     resp_hdr_ptr;
    logic [6:0]     resp_data_ptr;
    logic [2:0]     resp_data_array;
    logic           pop_vw_databyte;
    logic           detect_pc_rsp_withdata;
    logic           tx_with_cycletype;

    // espi_crc_gen rx outputs
    logic           pec_mismatch_rx;

    // espi_crc_gen tx outputs
    logic           pec_mismatch_tx;

    // espi_pc_channel outputs
    logic           pc_free;
    logic           np_free;
    logic           pc_rxfifo_avail;
    logic           np_rxfifo_avail;
    logic           pc_channel_ready;
    logic [7:0]     pc_rxfifo_rdata;
    logic [7:0]     np_rxfifo_rdata;
    logic [7:0]     txfifo_rdata;
    logic           get_pc_txfifo;
    logic           get_np_txfifo;
    logic [31:0]    pc_short_data;
    logic           pc_short_data_valid;
    logic           np_txfifo_avail;
    logic           pc_txfifo_avail;

    // espi_vw_channel outputs
    logic           vw_channel_ready;
    logic           vwire_avail;
    logic [7:0]     vw_data;
    logic [7:0]     vw_index;
    logic [6:0]     vw_count;
    
    // espi_oob_channel outputs
    logic           oob_free;
    logic           oob_channel_ready;
    logic [7:0]     oob_rxfifo_rdata;
    logic [7:0]     oob_txfifo_rdata;
    logic           get_oob_txfifo;
    logic           oob_txfifo_empty;

    // Locally driven
    logic           read_status;
    logic           read_status_reg;
    logic           read_status_regx2;
    logic           read_error;
    logic           read_error_reg;
    logic           read_error_regx2;
    logic           read_control;
    logic           read_control_reg;
    logic           read_control_regx2;
    logic           write_control_reg;
    logic           write_error_reg;
    logic           tx_gen_waitstate;
    logic           tx_gen_waitstate_reg;
    logic           pec_mismatch;
    logic           invalid_putfifo;
    logic           invalid_getfifo;
    logic           malform_vw_packet;
    logic           malform_pc_packet;
    logic           error_condition1;
    logic           error_condition2;
    logic           ip_reset_n;
    logic [6:0]     max_vw_count_int;
    logic [6:0]     payload_addr_boundary;
    logic [6:0]     max_payload_byte;
    logic [6:0]     readreq_addr_boundary;
    logic [6:0]     max_readreq_byte;
    logic           read_oob_rxfifo;
    logic           read_oob_rxfifo_reg;
    logic           read_oob_rxfifo_regx2;
    logic           write_oob_txfifo;
    logic           write_np_txfifo;
    logic           write_pc_txfifo;
    logic [7:0]     txfifo_wdata;
    logic           avmm_read_1d;


// Slave AVMM interface
assign read_status     = (avmm_read && avmm_address == 5'h00);
assign read_control    = (avmm_read && avmm_address == 5'h01);
assign read_error      = (avmm_read && avmm_address == 5'h06);
assign read_oob_rxfifo = (avmm_read && avmm_address == 5'h08);
assign avmm_readdata   = (read_status_regx2)    ? {16'd0,espi_status_reg} :        // read data latency = 2
                         (read_control_regx2)   ? 32'b0 :
                         (read_error_regx2)     ? {{24{1'b0}}, error_reg} :
                         (read_oob_rxfifo_regx2)? {{24{1'b0}}, oob_rxfifo_rdata} :
                         32'h1d53_1d53;

assign write_control_reg = (avmm_write && avmm_address == 5'h01);
assign write_pc_txfifo   = (avmm_write && avmm_address == 5'h03);
assign write_np_txfifo   = (avmm_write && avmm_address == 5'h05);
assign write_error_reg   = (avmm_write && avmm_address == 5'h06);
assign write_oob_txfifo  = (avmm_write && avmm_address == 5'h09);
assign txfifo_wdata = avmm_writedata[7:0];

assign ip_reset_n = espi_reset_n && reset_n;

assign max_vw_count_int = max_vw_count + 6'h1;   //max_vw_count + 1 because its 0-base value
assign malform_vw_packet = (vw_data_ptr > max_vw_count_int);

assign invalid_putfifo = ((~pc_free && rx_detect_command_end && detect_put_pc_rxfifo) ||
                          (~np_free && rx_detect_command_end && detect_put_np_rxfifo) ||
                          (~oob_free && rx_detect_command_end && detect_put_oob_rxfifo));

assign invalid_getfifo = ((~pc_txfifo_avail && rx_detect_command_end && detect_getpc) ||
                          (~np_txfifo_avail && rx_detect_command_end && detect_getnp) ||
                          (~vwire_avail && rx_detect_command_end && detect_getvwire) ||
                          (~oob_txfifo_avail && rx_detect_command_end && detect_getoob));

assign irq = interrupt;

always @(posedge clk or negedge ip_reset_n) begin
    if (!ip_reset_n) begin
        max_payload_byte <= {7{1'b0}};
        max_readreq_byte <= {7{1'b0}};
    end
    else begin
        if (max_pc_payload_size == 3'b001)
            max_payload_byte <= 7'd64;

        if (max_pc_readreq_size == 3'b001)
            max_readreq_byte <= 7'd64;
    end
end

always @(posedge clk or negedge ip_reset_n) begin
    if (!ip_reset_n) begin
        payload_addr_boundary  <= 7'h0;
        readreq_addr_boundary  <= 7'h0;
    end
    else begin
        payload_addr_boundary  <= max_payload_byte - 7'h1;
        readreq_addr_boundary  <= max_readreq_byte - 7'h1;
    end
end

always @(posedge clk or negedge ip_reset_n) begin
    if (!ip_reset_n) begin
        malform_pc_packet <= 1'b0;
    end
    else begin
        if (detect_pc_cmd_withdata && rx_detect_header_end &&
            (((addr_byte[6:0] & payload_addr_boundary) + length_byte[6:0]) > max_payload_byte))
            // for memory wite and completion with data                          
            malform_pc_packet <= 1'b1;
        else if (detect_putnp && rx_detect_header_end &&
                 (((addr_byte[6:0] & readreq_addr_boundary) + length_byte) > max_readreq_byte))
            // for memory read
            malform_pc_packet <= 1'b1;
        else
            malform_pc_packet <= 1'b0;
    end
end


assign pec_mismatch = pec_mismatch_rx | pec_mismatch_tx;

always @(posedge clk or negedge ip_reset_n) begin
    if (!ip_reset_n) begin
        error_condition1 <= 1'b0; // condition to issue no-RESPONSE
    end
    else if (stop_det) begin
        error_condition1 <= 1'b0;
    end
    else if (invalid_cmd || invalid_cycletype || pec_mismatch) begin
        error_condition1 <= 1'b1;
    end
end

always @(posedge clk or negedge ip_reset_n) begin
    if (!ip_reset_n) begin
        error_condition2 <= 1'b0; // condition to issue fatal error response
    end
    else if (stop_det) begin
        error_condition2 <= 1'b0;
    end
    else if (invalid_putfifo || invalid_getfifo || malform_vw_packet || malform_pc_packet) begin
        error_condition2 <= 1'b1;
    end
end

always @(posedge clk or negedge reset_n) begin
    if (!reset_n) begin
        tx_gen_waitstate_reg  <= 1'b0;
        read_status_reg       <= 1'b0;
        read_status_regx2     <= 1'b0;
        read_error_reg        <= 1'b0;
        read_error_regx2      <= 1'b0;
        read_oob_rxfifo_reg   <= 1'b0;
        read_oob_rxfifo_regx2 <= 1'b0;
        avmm_read_1d          <= 1'b0;
        avmm_readdatavalid    <= 1'b0;
        read_control_reg      <= 1'b0;
        read_control_regx2    <= 1'b0;
    end
    else begin
        tx_gen_waitstate_reg <= tx_gen_waitstate;
        read_status_regx2    <= read_status_reg;
        read_error_regx2     <= read_error_reg;
        read_oob_rxfifo_reg  <= read_oob_rxfifo;
        read_oob_rxfifo_regx2<= read_oob_rxfifo_reg;
        avmm_read_1d         <= avmm_read;
        avmm_readdatavalid   <= avmm_read_1d;
        read_status_reg      <= read_status;
        read_error_reg       <= read_error;
        read_control_reg     <= read_control;
        read_control_regx2   <= read_control_reg;
    end
end

generate if (CHANNEL_SUPPORT[0]) begin: pc_channel_enable_blk

    logic       pc_error_condition;
    logic       flush_pc_fifo;
    logic       io_flush_fifo;

always @(posedge clk or negedge ip_reset_n) begin
    if (!ip_reset_n) begin
        pc_error_condition <= 1'b0; // condition to drop pc command
    end
    else if (stop_det) begin
        pc_error_condition <= 1'b0;
    end
    else if (invalid_cmd || invalid_cycletype || pec_mismatch || invalid_putfifo || invalid_getfifo ||
             malform_pc_packet) begin
        pc_error_condition <= 1'b1;
    end
end

assign flush_pc_fifo = pc_error_condition;
assign io_flush_fifo = pc_error_condition;

espi_pc_channel #(
    .HDRBYTE_ARR          (HDRBYTE_ARR),
    .DATABYTE_ARR         (DATABYTE_ARR),
    .PC_RXFIFO_SIZE       (PC_RXFIFO_SIZE),
    .PC_RXFIFO_WIDTHU     (PC_RXFIFO_WIDTHU),
    .PC_TXFIFO_SIZE       (PC_TXFIFO_SIZE),
    .PC_TXFIFO_WIDTHU     (PC_TXFIFO_WIDTHU),
    .DEVICE_FAMILY        (DEVICE_FAMILY)
)  espi_pc_channel_inst (
    .clk                          (clk),
    .reset_n                      (reset_n),
    .pltrst_n                     (pltrst_n),
    .pc_channel_reset             (pc_channel_reset),
    .pc_error_condition           (pc_error_condition),
    .pec_mismatch                 (pec_mismatch),
    .flush_pc_fifo                (flush_pc_fifo),
    .stop_det                     (stop_det),
    .pc_channel_en                (pc_channel_en),
    .txfifo_wdata                 (txfifo_wdata),
    .rx_hdr_array_cnt             (rx_hdr_array_cnt),
    .rx_data_array_cnt            (rx_data_array_cnt),
    .data_byte                    (data_byte),
    .header_byte                  (header_byte),
    .command_byte                 (command_byte),
    .rx_detect_header             (rx_detect_header),
    .rx_detect_header_end         (rx_detect_header_end),
    .rx_detect_data               (rx_detect_data),
    .rx_detect_data_end           (rx_detect_data_end),
    .rx_detect_crc_end            (rx_detect_crc_end),
    .rx_detect_command            (rx_detect_command),
    .tx_gen_command               (tx_gen_command),
    .tx_gen_header                (tx_gen_header),
    .tx_gen_data                  (tx_gen_data),
    .spiclk_cnt_done_lh           (spiclk_cnt_done_lh),
    .spiclk_cnt_done_hl           (spiclk_cnt_done_hl),
    .detect_put_np_rxfifo         (detect_put_np_rxfifo),
    .detect_put_pc_rxfifo         (detect_put_pc_rxfifo),
    .detect_get_np_txfifo         (detect_get_np_txfifo),
    .detect_get_pc_txfifo         (detect_get_pc_txfifo),
    .detect_memrd_short           (detect_memrd_short),
    .detect_memwr_short           (detect_memwr_short),
    .detect_iord_short            (detect_iord_short),
    .detect_iowr_short            (detect_iowr_short),
    .detect_short_1b              (detect_short_1b),
    .detect_short_2b              (detect_short_2b),
    .detect_short_4b              (detect_short_4b),
    .write_pc_txfifo              (write_pc_txfifo),
    .write_np_txfifo              (write_np_txfifo),
    .np_connected                 (np_connected),
    .np_txfifo_avail              (np_txfifo_avail),
    .pc_txfifo_avail              (pc_txfifo_avail),
    .pc_free                      (pc_free),
    .np_free                      (np_free),
    .pc_rxfifo_avail              (pc_rxfifo_avail),
    .np_rxfifo_avail              (np_rxfifo_avail),
    .pc_channel_ready             (pc_channel_ready),
    .pc_rxfifo_rdata              (pc_rxfifo_rdata),
    .np_rxfifo_rdata              (np_rxfifo_rdata),
    .txfifo_rdata                 (txfifo_rdata),
    .get_pc_txfifo                (get_pc_txfifo),
    .get_np_txfifo                (get_np_txfifo),
    .pc_short_data                (pc_short_data),
    .pc_short_data_valid          (pc_short_data_valid),
    .mem_address                  (mem_address),
    .mem_write                    (mem_write),
    .mem_writedata                (mem_writedata),
    .mem_byteenable               (mem_byteenable),
    .mem_read                     (mem_read),
    .mem_readdata                 (mem_readdata),
    .mem_waitrequest              (mem_waitrequest),
    .io_address                   (io_address),
    .io_write                     (io_write),
    .io_writedata                 (io_writedata),
    .io_read                      (io_read),
    .io_readdata                  (io_readdata),
    .io_waitrequest               (io_waitrequest)
);

end
else begin : pc_channel_disable_blk
    assign pc_free = 0;
    assign np_free = 0;
    assign pc_rxfifo_avail = 0;
    assign np_rxfifo_avail = 0;
    assign get_pc_txfifo = 0;
    assign get_np_txfifo = 0;
    assign pc_channel_ready = 0;
    assign pc_rxfifo_rdata = {8{1'b0}};
    assign np_rxfifo_rdata = {8{1'b0}};
    assign txfifo_rdata = {8{1'b0}};
    assign np_txfifo_avail = 0;
    assign pc_txfifo_avail = 0;
    assign mem_address = 0;
    assign mem_write = 0;
    assign mem_writedata = 0;
    assign mem_byteenable = 0;
    assign mem_read = 0;
    assign io_address = 0;
    assign io_write = 0;
    assign io_writedata = 0;
    assign io_read = 0;
    assign pc_short_data = 0;
    assign pc_short_data_valid = 0;
end
endgenerate

assign io_reset = ~(reset_n & pltrst_n) | pc_channel_reset;

espi_condt_det espi_condt_det_inst (
    .clk                         (clk),
    .reset_n                     (reset_n),
    .espi_cs_n                   (espi_cs_n),
    .espi_clk                    (espi_clk),
    .espi_reset_n                (espi_reset_n),
    .espi_data_in                (espi_data_in),
    .espi_alert_n                (espi_alert_n),                                    
    .rx_detect_command           (rx_detect_command),
    .rx_detect_crc               (rx_detect_crc),
    .detect_rx_idle              (detect_rx_idle),
    .tx_gen_crc                  (tx_gen_crc),
    .detect_tx_idle              (detect_tx_idle),
    .update_status_reg           (update_status_reg),
    .opendrain_alert             (opendrain_alert),
    .alert_mode                  (alert_mode),
    .io_mode                     (io_mode),
    .tx_dataout_byte             (tx_dataout_byte),
    .error_condition1            (error_condition1),
    .trigger_output              (trigger_output),
    .rxshift_data_nxt2           (rxshift_data),
    .start_det                   (start_det),
    .stop_det                    (stop_det),
    .espi_data_out               (espi_data_out),
    .espi_cs_n_nxt2              (espi_cs_n_nxt2),
    .spiclk_cnt_done_lh          (spiclk_cnt_done_lh),
    .spiclk_cnt_done_hl          (spiclk_cnt_done_hl),
    .invalid_cs_deassertion      (invalid_cs_deassertion),
    .posted_cycle                (posted_cycle)
);

espi_tx_shifter espi_tx_shifter_inst (
    .clk                        (clk),
    .ip_reset_n                 (ip_reset_n),
    .rx_detect_crc              (rx_detect_crc),
    .rx_detect_crc_end          (rx_detect_crc_end),
    .tx_with_cycletype          (tx_with_cycletype),
    .detect_iord_short          (detect_iord_short),
    .detect_iowr_short          (detect_iowr_short),
    .detect_memrd_short         (detect_memrd_short),
    .detect_memwr_short         (detect_memwr_short),
    .detect_put_np_rxfifo       (detect_put_np_rxfifo),
    .error_condition1           (error_condition1),
    .error_condition2           (error_condition2),
    .stop_det                   (stop_det),
    .start_det                  (start_det),
    .resp_hdr_ptr               (resp_hdr_ptr),
    .resp_data_ptr              (resp_data_ptr),
    .resp_data_array            (resp_data_array),
    .io_mode                    (io_mode),
    .pc_short_data_valid        (pc_short_data_valid),
    .pc_txfifo_avail            (pc_txfifo_avail),
    .np_connected               (np_connected),
    .max_wait_state             (max_wait_state),
    .spiclk_cnt_done_hl         (spiclk_cnt_done_hl),
    .spiclk_cnt_done_lh         (spiclk_cnt_done_lh),
    .posted_cycle               (posted_cycle),
    .trigger_output             (trigger_output),
    .resp_header                (resp_header),
    .resp_cycletype             (resp_cycletype),
    .resp_cycletype_msb         (resp_cycletype_msb),
    .resp_data                  (resp_data),
    .resp_status                (resp_status),
    .pec_mismatch_tx            (pec_mismatch_tx),
    .tx_status_cnt              (tx_status_cnt),
    .tx_data_array_cnt          (tx_data_array_cnt),
    .tx_gen_command             (tx_gen_command),
    .tx_gen_header              (tx_gen_header),
    .tx_gen_cycletype           (tx_gen_cycletype),
    .tx_gen_length_h            (tx_gen_length_h),
    .tx_gen_length_l            (tx_gen_length_l),
    .tx_gen_data                (tx_gen_data),
    .tx_gen_status              (tx_gen_status),
    .tx_gen_crc                 (tx_gen_crc),
    .tx_dataout_byte            (tx_dataout_byte),
    .detect_tx_idle             (detect_tx_idle)
);


espi_resp_gen espi_resp_gen_inst (
    .clk                     (clk),
    .reset_n                 (reset_n),
    .stop_det                (stop_det),
    .status_reg_dataout      (status_reg_dataout),
    .tx_gen_status           (tx_gen_status),
    .tx_gen_command          (tx_gen_command),
    .tx_gen_data             (tx_gen_data),
    .tx_gen_header           (tx_gen_header),
    .tx_gen_cycletype        (tx_gen_cycletype),
    .tx_gen_length_h         (tx_gen_length_h),
    .tx_gen_length_l         (tx_gen_length_l),
    .spiclk_cnt_done_hl      (spiclk_cnt_done_hl),
    .spiclk_cnt_done_lh      (spiclk_cnt_done_lh),
    .tx_data_array_cnt       (tx_data_array_cnt),
    .config_reg_dataout      (config_reg_dataout),
    .pc_short_data           (pc_short_data),
    .pc_short_data_valid     (pc_short_data_valid),
    .txfifo_rdata            (txfifo_rdata),
    .oob_txfifo_rdata        (oob_txfifo_rdata),
    .detect_getvwire         (detect_getvwire),
    .detect_getstatus        (detect_getstatus),
    .detect_getconfig        (detect_getconfig),
    .detect_setconfig        (detect_setconfig),
    .detect_iord_short       (detect_iord_short),
    .detect_short_1b         (detect_short_1b),
    .detect_short_2b         (detect_short_2b),
    .detect_short_4b         (detect_short_4b),
    .detect_memrd_short      (detect_memrd_short),
    .detect_getpc            (detect_getpc),
    .detect_getnp            (detect_getnp),
    .detect_getoob           (detect_getoob),
    .detect_putoob           (detect_putoob),
    .resp_data               (resp_data),
    .resp_status             (resp_status),
    .resp_header             (resp_header),
    .resp_cycletype          (resp_cycletype),
    .resp_cycletype_msb      (resp_cycletype_msb),
    .vw_data                 ({vw_data, vw_index}),
    .vw_count                (vw_count),
    .vwire_avail             (vwire_avail),
    .resp_hdr_ptr            (resp_hdr_ptr),
    .resp_data_ptr           (resp_data_ptr),
    .resp_data_array         (resp_data_array),
    .pop_vw_databyte         (pop_vw_databyte),
    .detect_pc_rsp_withdata  (detect_pc_rsp_withdata),
    .tx_with_cycletype       (tx_with_cycletype)
);

generate if (CHANNEL_SUPPORT[1]) begin: vw_channel_enable_blk

logic malform_vw_packet_reg, pec_mismatch_reg;
always @(posedge clk or negedge ip_reset_n) begin
    if (!ip_reset_n) begin
        malform_vw_packet_reg <= 1'b0; // condition to issue fatal error response
        pec_mismatch_reg      <= 1'b0;
    end
    else if (stop_det) begin
        malform_vw_packet_reg <= 1'b0;
        pec_mismatch_reg      <= 1'b0;
    end
    else if (malform_vw_packet) begin
        malform_vw_packet_reg <= 1'b1;
    end
    else if (pec_mismatch) begin
        pec_mismatch_reg      <= 1'b1;
    end
end

espi_vw_channel #(
    .VW_FIFO_SIZE (VW_FIFO_SIZE),
    .VW_FIFO_WIDTHU(VW_FIFO_WIDTHU),
    .DATABYTE_ARR  (DATABYTE_ARR),
    .DEVICE_FAMILY (DEVICE_FAMILY)
) espi_vw_channel_inst (
    .clk                          (clk),
	 .reset_n                      (reset_n),
    .espi_reset_n                  (espi_reset_n),
    .rx_data_array_cnt            (rx_data_array_cnt),
    .vw_channel_en                (vw_channel_en),
    .malform_vw_packet_reg        (malform_vw_packet_reg),
    .pec_mismatch_reg             (pec_mismatch_reg),
    .rsmrst_n                     (rsmrst_n),
    .data_byte                    (data_byte),
    .stop_det                     (stop_det),
    .detect_putvwire              (detect_putvwire),
    .spiclk_cnt_done_hl           (spiclk_cnt_done_hl),
    .slave_boot_load_done         (slave_boot_load_done),
    .slave_boot_load_status       (slave_boot_load_status),
    .oob_rst_ack                  (oob_rst_ack),
    .wake_n                       (wake_n),
    .nmi_n                        (nmi_n),
    .pme_n                        (pme_n),
    .sci_n                        (sci_n),
    .smi_n                        (smi_n),
    .rcin_n                       (rcin_n),
    .host_rst_ack                 (host_rst_ack),
    .pop_vw_databyte              (pop_vw_databyte),
    .max_vw_count_int             (max_vw_count_int),
    .irq                          (vw_irq),
    .plti                         (vw_plti),
    .plto                         (vw_plto),
    .gpi                          (vw_gpi),
    .gpo                          (vw_gpo),
    .vw_channel_ready             (vw_channel_ready),
    .vwire_avail                  (vwire_avail),
    .vw_data                      (vw_data),
    .vw_index                     (vw_index),
    .vw_count                     (vw_count),
    .slp_s3_n                     (slp_s3_n),
    .slp_s4_n                     (slp_s4_n),
    .slp_s5_n                     (slp_s5_n),
    .sus_stat_n                   (sus_stat_n),
    .pltrst_n                     (pltrst_n),
    .oob_rst_warn                 (oob_rst_warn),
    .host_rst_warn                (host_rst_warn),
    .smiout_n                     (smiout_n),
    .nmiout_n                     (nmiout_n),
    .error_condition1             (error_condition1),
    .error_nonfatal               (error_nonfatal),
    .error_fatal                  (error_fatal   )

);
end
else begin: vw_channel_disable_blk
    assign vw_channel_ready = 0;
    assign vwire_avail = 0;
    assign vw_data = 8'h0;
    assign vw_index = 8'h0;
    assign vw_count = 7'h0;
    assign pltrst_n = 1'b1;
end
endgenerate

generate if (CHANNEL_SUPPORT[2]) begin: oob_channel_enable_blk

logic oob_error_condition, flush_oob_fifo;

always @(posedge clk or negedge ip_reset_n) begin
    if (!ip_reset_n) begin
        oob_error_condition <= 1'b0; // condition to drop pc command
    end
    else if (stop_det) begin
        oob_error_condition <= 1'b0;
    end
    else if (invalid_cmd || invalid_cycletype || pec_mismatch || invalid_putfifo || invalid_getfifo) begin
        oob_error_condition <= 1'b1;
    end
end

always @(posedge clk or negedge ip_reset_n) begin
    if (!ip_reset_n)
        flush_oob_fifo <= 1'b0;
    else if (stop_det) begin
        flush_oob_fifo <= 1'b0;
    end
    else if (invalid_cmd || invalid_cycletype || pec_mismatch || invalid_putfifo || invalid_getfifo) begin
        flush_oob_fifo <= 1'b1;
    end
end

espi_oob_channel #(
    .HDRBYTE_ARR          (HDRBYTE_ARR),
    .DATABYTE_ARR         (DATABYTE_ARR),
    .OOB_RXFIFO_SIZE      (OOB_RXFIFO_SIZE),
    .OOB_RXFIFO_WIDTHU    (OOB_RXFIFO_WIDTHU),
    .OOB_TXFIFO_SIZE      (OOB_TXFIFO_SIZE),
    .OOB_TXFIFO_WIDTHU    (OOB_TXFIFO_WIDTHU),
    .DEVICE_FAMILY        (DEVICE_FAMILY)
)  espi_oob_channel_inst (
    .clk                          (clk),
    .reset_n                      (reset_n),
    .oob_channel_reset            (oob_channel_reset),
    .oob_error_condition          (oob_error_condition),
    .pec_mismatch                 (pec_mismatch),
    .flush_oob_fifo               (flush_oob_fifo),
    .stop_det                     (stop_det),
    .oob_channel_en               (oob_channel_en),
    .read_oob_rxfifo              (read_oob_rxfifo),
    .txfifo_wdata                 (avmm_writedata[7:0]),
    .rx_hdr_array_cnt             (rx_hdr_array_cnt),
    .rx_data_array_cnt            (rx_data_array_cnt),
    .data_byte                    (data_byte),
    .header_byte                  (header_byte),
    .command_byte                 (command_byte),
    .rx_detect_header             (rx_detect_header),
    .rx_detect_header_end         (rx_detect_header_end),
    .rx_detect_data               (rx_detect_data),
    .rx_detect_data_end           (rx_detect_data_end),
    .rx_detect_crc_end            (rx_detect_crc_end),
    .rx_detect_command            (rx_detect_command),
    .tx_gen_command               (tx_gen_command),
    .tx_gen_header                (tx_gen_header),
    .tx_gen_data                  (tx_gen_data),
    .spiclk_cnt_done_lh           (spiclk_cnt_done_lh),
    .spiclk_cnt_done_hl           (spiclk_cnt_done_hl),
    .detect_put_oob_rxfifo        (detect_put_oob_rxfifo),
    .detect_get_oob_txfifo        (detect_get_oob_txfifo),
    .write_oob_txfifo             (write_oob_txfifo),
    .oob_free                     (oob_free),
    .oob_rxfifo_avail             (oob_rxfifo_avail),
    .oob_channel_ready            (oob_channel_ready),
    .oob_rxfifo_rdata             (oob_rxfifo_rdata),
    .oob_txfifo_rdata             (oob_txfifo_rdata),
    .get_oob_txfifo               (get_oob_txfifo),
    .oob_txfifo_empty             (oob_txfifo_empty)
);
end
else begin : oob_channel_disable_blk
    assign oob_free = 0;
    assign oob_rxfifo_avail = 0;
    assign get_oob_txfifo = 0;
    assign oob_txfifo_empty = 0;
    assign oob_channel_ready = 0;
    assign oob_rxfifo_rdata = {8{1'b0}};
    assign oob_txfifo_rdata = {8{1'b0}};
end
endgenerate

espi_cmd_det #(
    .DATABYTE_ARR  (DATABYTE_ARR),
    .HDRBYTE_ARR   (HDRBYTE_ARR)
) espi_cmd_det_inst (
    .clk                           (clk),
    .reset_n                       (reset_n),
    .stop_det                      (stop_det),
    .rx_detect_command_end         (rx_detect_command_end),
    .rx_detect_cycletype_end       (rx_detect_cycletype_end),
    .rx_detect_header              (rx_detect_header),
    .command_byte                  (command_byte),
    .data_byte                     (data_byte),
    .header_byte                   (header_byte),
    .length_byte                   (length_byte),
    .crc_byte                      (crc_byte),
    .cycletype_byte                (cycletype_byte),
    .cmd_cycletype_msb             (cmd_cycletype_msb),
    .config_reg_addr               (config_reg_addr),
    .config_reg_datain             (config_reg_datain),
    .cmd_hdr_ptr                   (cmd_hdr_ptr),
    .cmd_data_ptr                  (cmd_data_ptr),
    .cmd_data_array                (cmd_data_array),
    .detect_getvwire               (detect_getvwire),
    .detect_getstatus              (detect_getstatus),
    .detect_getconfig              (detect_getconfig),
    .detect_setconfig              (detect_setconfig),
    .detect_putpc                  (detect_putpc),
    .detect_putnp                  (detect_putnp),
    .detect_getpc                  (detect_getpc),
    .detect_getnp                  (detect_getnp),
    .detect_putvwire               (detect_putvwire),
    .detect_put_np_rxfifo          (detect_put_np_rxfifo),
    .detect_put_pc_rxfifo          (detect_put_pc_rxfifo),
    .detect_get_np_txfifo          (detect_get_np_txfifo),
    .detect_get_pc_txfifo          (detect_get_pc_txfifo),
    .detect_pc_cmd_withdata        (detect_pc_cmd_withdata),
    .detect_iord_short             (detect_iord_short),
    .detect_iowr_short             (detect_iowr_short),
    .detect_short_1b               (detect_short_1b),
    .detect_short_2b               (detect_short_2b),
    .detect_short_4b               (detect_short_4b),
    .detect_memrd_short            (detect_memrd_short),
    .detect_memwr_short            (detect_memwr_short),
    .detect_reset                  (detect_reset),
    .detect_putoob                 (detect_putoob),
    .detect_getoob                 (detect_getoob),
    .detect_put_oob_rxfifo         (detect_put_oob_rxfifo),
    .detect_get_oob_txfifo         (detect_get_oob_txfifo),
    .posted_cycle                  (posted_cycle),
    .invalid_cmd                   (invalid_cmd),
    .invalid_cycletype             (invalid_cycletype),
    .rx_with_cycletype             (rx_with_cycletype),
    .vw_data_ptr                   (vw_data_ptr),
    .addr_ptr                      (addr_ptr)
);

espi_rx_shifter #(
    .DATABYTE_ARR  (DATABYTE_ARR),
    .HDRBYTE_ARR   (HDRBYTE_ARR)
) espi_rx_shifter_inst (
    .clk                          (clk),
    .ip_reset_n                   (ip_reset_n),
    .invalid_cmd                  (invalid_cmd),
    .invalid_cycletype            (invalid_cycletype),
    .detect_reset                 (detect_reset),
    .spiclk_cnt_done_lh           (spiclk_cnt_done_lh),
    .spiclk_cnt_done_hl           (spiclk_cnt_done_hl),
    .rxshift_data                 (rxshift_data),
    .start_det                    (start_det),
    .stop_det                     (stop_det),
    .crc_en                       (crc_en),
    .cmd_hdr_ptr                  (cmd_hdr_ptr),
    .cmd_data_ptr                 (cmd_data_ptr),
    .cmd_data_array               (cmd_data_array),
    .pec_mismatch_rx              (pec_mismatch_rx),
    .rx_with_cycletype            (rx_with_cycletype),
    .rx_hdr_array_cnt             (rx_hdr_array_cnt),
    .rx_data_array_cnt            (rx_data_array_cnt),
    .command_byte                 (command_byte),
    .header_byte                  (header_byte),
    .data_byte                    (data_byte),
    .crc_byte                     (crc_byte),
    .cycletype_byte               (cycletype_byte),
    .cmd_cycletype_msb            (cmd_cycletype_msb),
    .length_byte                  (length_byte),
    .addr_byte                    (addr_byte),
    .rx_detect_command            (rx_detect_command),
    .rx_detect_header             (rx_detect_header),
    .rx_detect_data               (rx_detect_data),
    .rx_detect_crc                (rx_detect_crc),
    .rx_detect_cycletype_end      (rx_detect_cycletype_end),
    .rx_detect_command_end        (rx_detect_command_end),
    .rx_detect_header_end         (rx_detect_header_end),
    .rx_detect_data_end           (rx_detect_data_end),
    .rx_detect_crc_end            (rx_detect_crc_end),
    .detect_rx_idle               (detect_rx_idle)
);

espi_register #(
    .IO_MODE_RANGE              (IO_MODE_RANGE),
    .OPEN_DRAIN_ALERT_EN        (OPEN_DRAIN_ALERT_EN),
    .MAX_FREQ_RANGE             (MAX_FREQ_RANGE),
    .CHANNEL_SUPPORT            (CHANNEL_SUPPORT),
    .MAX_PC_PAYLOAD_SIZE_RANGE  (MAX_PC_PAYLOAD_SIZE_RANGE),
    .MAX_OOB_PAYLOAD_SIZE_RANGE (MAX_OOB_PAYLOAD_SIZE_RANGE),
    .MAX_VW_COUNT_SUPPORTED     (MAX_VW_COUNT_SUPPORTED)
) espi_register_inst (
    .clk                    (clk),
    .ip_reset_n             (ip_reset_n),
    .detect_reset           (detect_reset),
    .pltrst_n               (pltrst_n),
    .espi_cs_n_nxt2         (espi_cs_n_nxt2),
    .start_det              (start_det),
    .write_error_reg        (write_error_reg),
    .write_control_reg      (write_control_reg),
    .avmm_writedata         (avmm_writedata[7:0]),
    .invalid_cmd            (invalid_cmd),
    .invalid_cycletype      (invalid_cycletype),
    .crc_error              (pec_mismatch),
    .invalid_cs_deassertion (invalid_cs_deassertion),
    .invalid_putfifo        (invalid_putfifo),
    .invalid_getfifo        (invalid_getfifo),
    .malform_pc_packet      (malform_pc_packet),
    .malform_vw_packet      (malform_vw_packet),
    .stop_det               (stop_det),
    .tx_gen_status          (tx_gen_status),
    .detect_getstatus       (detect_getstatus),
    .detect_getconfig       (detect_getconfig),
    .detect_setconfig       (detect_setconfig),
    .vwire_avail            (vwire_avail),
    .pc_rxfifo_avail        (pc_rxfifo_avail),
    .np_rxfifo_avail        (np_rxfifo_avail),
    .oob_rxfifo_avail       (oob_rxfifo_avail),
    .np_free                (np_free),
    .pc_free                (pc_free),
    .oob_free               (oob_free),
    .get_pc_txfifo          (get_pc_txfifo),
    .get_np_txfifo          (get_np_txfifo),
    .get_oob_txfifo         (get_oob_txfifo),
    .oob_txfifo_empty       (oob_txfifo_empty),
    .pc_channel_ready       (pc_channel_ready),
    .oob_channel_ready      (oob_channel_ready),
    .vw_channel_ready       (vw_channel_ready),
    .config_reg_addr        (config_reg_addr),
    .config_reg_datain      (config_reg_datain),
    .max_wait_state         (max_wait_state),
    .io_mode                (io_mode),
    .config_reg_dataout     (config_reg_dataout),
    .status_reg_dataout     (status_reg_dataout),
    .crc_en                 (crc_en),
    .resp_mod_en            (resp_mod_en),
    .alert_mode             (alert_mode),
    .opendrain_alert        (opendrain_alert),
    .freq_value             (freq_value),
    .max_pc_readreq_size    (max_pc_readreq_size),
    .max_pc_payload_size    (max_pc_payload_size),
    .bus_master_en          (bus_master_en),
    .pc_channel_en          (pc_channel_en),
    .max_oob_payload_size   (max_oob_payload_size),
    .max_vw_count           (max_vw_count),            // 0-base count
    .oob_channel_en         (oob_channel_en),
    .vw_channel_en          (vw_channel_en),
    .update_status_reg      (update_status_reg),
    .np_txfifo_avail        (np_txfifo_avail),
    .pc_txfifo_avail        (pc_txfifo_avail),
    .oob_txfifo_avail       (oob_txfifo_avail),
    .interrupt              (interrupt),
    .pc_channel_reset       (pc_channel_reset),
    .oob_channel_reset      (oob_channel_reset),
    .avalon_status_reg      (avalon_status_reg),
    .error_reg              (error_reg),
    .device_id_reg          (device_id_reg),
    .general_config_reg     (general_config_reg),
    .channel0_config_reg    (channel0_config_reg),
    .channel1_config_reg    (channel1_config_reg),
    .channel2_config_reg    (channel2_config_reg),
    .channel3_config_reg    (channel3_config_reg),
    .espi_status_reg        (espi_status_reg)         //new added
);

endmodule
